home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 013 / sd3.arc / SD3.ASM < prev    next >
Assembly Source File  |  1987-06-15  |  60KB  |  1,580 lines

  1. ;------------------------------------------------------------------------------;
  2. ;                                                                              ;
  3. ; Switch Directory - SD    Copyright (c) Stephen M. Falatko, 1987              ;
  4. ;                                                                              ;
  5. ;     Switch  Directory  (SD)  is  a  utility that allows easy switching       ;
  6. ;     between subdirectories and drives  with a  minimum of  typing.  SD       ;
  7. ;     has  been  designed  to  replace  the  DOS  CD command and provide       ;
  8. ;     enhancements to the CD  command.    SD  allows  you  to  specify a       ;
  9. ;     specific  subdirectory  name,  a combination of subdirectory names       ;
  10. ;     and search switches or a complete path specifier.  All features of       ;
  11. ;     SD work  across disk  drives.  If you have made a mistake, hitting       ;
  12. ;     Ctrl-Brk while SD is searching will  break you  out of  SD and put       ;
  13. ;     you back  in the subdirectory you started in.  With version 3.0 SD       ;
  14. ;     will also except a 'minimum match' to a subdirectory name (i.e. if       ;
  15. ;     you have  only one directory that begins with 'LO' then SD LO will       ;
  16. ;     take you there even if the full name is LOTUS).  Given a full path       ;
  17. ;     designation, SD  switches to the specified path without searching.       ;
  18. ;     An important feature of SD is that it can be enqueued to PCED, the       ;
  19. ;     DOS Command  EDitor by  Chris Dunford (and its public domain             ;
  20. ;     counterpart CED.  When enqueued SD will seem like and extension of       ;
  21. ;     DOS.  In this configuration SD dos NOT have to be present anywhere       ;
  22. ;     on your disk drives.                                                     ;
  23. ;                                                                              ;
  24. ;                                                                              ;
  25. ;Usage                                                                         ;
  26. ;                                                                              ;
  27. ;    [d:\....]>SD [drive][command specification]                               ;
  28. ;                                                                              ;
  29. ;          [drive] - the drive to search. (if not searching the current drive) ;
  30. ;                                                                              ;
  31. ;          [command specification]                                             ;
  32. ;                                                                              ;
  33. ;                  - this can be any valid CD command or any combination of \  ;
  34. ;                    (for specific paths) or / (for search below the current   ;
  35. ;                    dir) (if blank SD returns the current path).              ;
  36. ;                                                                              ;
  37. ;    A valid command could be:                                                 ;
  38. ;                                                                              ;
  39. ;             SD c:\turbo/source\myprog                                        ;
  40. ;                                                                              ;
  41. ;             This would switch to c:\turbo then search its subdirectories for ;
  42. ;             a source subdirectory then switch to the myprog subdirectory.    ;
  43. ;             If no \ or / is specified then the entire disk is searched for   ;
  44. ;             the desired subdirectory starting with the current directory.    ;
  45. ;                                                                              ;
  46. ;    Special Command:  SD [c will enqueue SD to the CED program (p for PCED)   ;
  47. ;                      SD [c+ will enqueue SD without online help.             ;
  48. ;                                                                              ;
  49. ;                                                                              ;
  50. ;                                                                              ;
  51. ;The source code was originally developed from Vern Buerg's LDIR program and   ;
  52. ;Charles Wooster's WHISK program.  PrintS and GetDir are Copyrighted by there  ;
  53. ;authors.                                                                      ;
  54. ;                                                                              ;
  55. ;6/04/87 - Stephen Falatko                                                     ;
  56. ;                                                                              ;
  57. ;Written for the A86 assembler (All numbers with leading 0 are hex)            ;
  58. ;                                                                              ;
  59. ;------------------------------------------------------------------------------;
  60.  
  61.  
  62. ;---------------------------------------------------------------------------;
  63. ;                                                                           ;
  64. ;     Macros and Equates                                                    ;
  65. ;                                                                           ;
  66. ;---------------------------------------------------------------------------;
  67.  
  68.  
  69. LF           Equ     10
  70. CR           Equ     13
  71. Stopper      Equ     255                    ;Ends print strings
  72.  
  73. ;
  74. ;  These equates are for DOS functions.  They are all in hex.  A86 defaults
  75. ;  to hex if the number has a leading 0.
  76. ;
  77.  
  78. SetDrive     Equ     0E
  79. CurrentDisk  Equ     019                     ;Get current disk
  80. SetDTA       Equ     01A                     ;Set data transfer area
  81. ChangeDir    Equ     03B                     ;Change directory
  82. GetPath      Equ     047                     ;Get current directory
  83.  
  84.  
  85. Change_Dir MACRO
  86.  
  87.         Mov DX,Offset #1
  88.         Mov AH,ChangeDir
  89.         Int 021
  90. #EM
  91.  
  92. Set_Drive MACRO
  93.  
  94.         Mov AH,SetDrive
  95.         Int 021
  96. #EM
  97.  
  98. Get_Path MACRO
  99.  
  100.         Mov AH,GetPath
  101.         Int 021
  102. #EM
  103.  
  104. Current_Disk MACRO
  105.  
  106.         Mov AH,CurrentDisk
  107.         Int 021
  108. #EM
  109.  
  110. ;---------------------------------------------------------------------------;
  111. ;                                                                           ;
  112. ;        Here is where the code begins                                      ;
  113. ;                                                                           ;
  114. ;---------------------------------------------------------------------------;
  115.  
  116. CODE SEGMENT
  117.  
  118.       Org    0100
  119. Main:
  120.       Jmp    Start
  121.  
  122. ;---------------------------------------------------------------------------;
  123. ;                                                                           ;
  124. ;     Data Areas, Constants, Etc.                                           ;
  125. ;                                                                           ;
  126. ;---------------------------------------------------------------------------;
  127.  
  128. Version      Db      CR,'Switch Directory  3.0',CR,LF
  129. Copyright    Db      'Copyright (c) 1987 by Stephen M. Falatko',CR,LF
  130. FakeEOF      Db      26
  131.  
  132. Errlvl       Db      0                       ;DOS return code
  133.  
  134. ;
  135. ;  These are flags set by the command line processing
  136. ;
  137. ;
  138.  
  139. RootFlag     Db      0                  ; signal indicating default to root (0)
  140. CDFlag       Db      0                  ; signal of specific path (1)
  141. OneDeepFlag  Db      0                  ; search only current dir (1)
  142.  
  143. ;
  144. ;  This flag is set to indicate that a subdirectory has been found (ie if its
  145. ;  0 at the end then we did not find the subdirectory)
  146. ;
  147.  
  148. Done_Flag    Db      0                  ; found subdir during search
  149.  
  150. ;
  151. ;  This flag is set if SD is enqueued to CED
  152. ;
  153.  
  154. CEDFlag      Db      0
  155.  
  156. ;
  157. ;  If this flag is set then help is available if ? is entered on the
  158. ;  command line
  159. ;
  160.  
  161. HelpFlag     Db      1
  162.  
  163. ;
  164. ;  These variables hold the systems Ctrl-Break address so we can restore
  165. ;  it when we exit
  166. ;
  167.  
  168. CtrlBrkOff   Dw      0
  169. CtrlBrkSeg   Dw      0
  170.  
  171. ;
  172. ;  Here we will store the desired subdirectory (and drive if selected)
  173. ;  as well as the original path and drive
  174. ;
  175.  
  176. Sub_Dir      Db      63 Dup (0)              ; The sub dir we want to change to
  177.  
  178. ScratchDirStart Db 'x:\'                     ; This is a scratch area for the
  179. ScratchDir      Db 63 Dup (0)                ; GetDir function
  180.  
  181. OrigDr       Db      'x:'                    ; Original drive
  182. OrigDir      Db      '\',63 Dup (0)          ; and path
  183.  
  184. RootDir      Db      'x:\',0                 ; To get vol label
  185.  
  186. Count        Dw      0                       ; Number of args on command line
  187.  
  188. ;
  189. ;  These variables are used by the search routine
  190. ;
  191.  
  192. DtaPointer   Dw      DtaAreaBegin            ; Pointer to our DTA area
  193. Direction    Db      0                       ; Flag to indicate search subdirs
  194.                                              ; of the current dir or not
  195. BackOneDir   Db      '..',0                  ; Asciiz 'filename' to backup
  196.                                              ; one directory
  197. SearchAsciiZ Db      '*.*',0                 ; Search filename
  198.  
  199. ;
  200. ;     Error messages
  201. ;
  202.  
  203. NoHelp         Db  CR,LF,'ERROR - Installed without help',CR,LF,Stopper
  204.  
  205. ErrorMsgs      Db  CR,LF,'Illegal drive specifier - must be A to z',CR,LF,Stopper
  206.                Db  CR,LF,'Maximum of 64 characters on command line',CR,LF,Stopper
  207.                Db  CR,LF,'Illegal character on command line       ',CR,LF,Stopper
  208.                Db  CR,LF,'Currently in root directory             ',CR,LF,Stopper
  209.                Db  CR,LF,'Command line contains an invalid path   ',CR,LF,Stopper
  210.                Db  CR,LF,'Subdirectory Not Found                  ',CR,LF,Stopper
  211.  
  212. Start:
  213. ;
  214. ;  If we are enqueued as a CED command we must preserve the DS register
  215. ;  and null out the CED internal command line.  (When we leave we don't
  216. ;  want DOS to do anything)
  217. ;
  218.       CS Cmp CEDFlag,1               ; Enqueued to CED ?
  219.       Jne    NoCED
  220.  
  221.       Mov    B [SI],CR               ; Null out the CED Buffer for our exit
  222.       Mov    BP,DX                   ; save pointer to CED internal buffer
  223.  
  224.       Mov    ES,DS                   ; This saves the DS value if we are
  225.                                      ; enqueued to CED (points to CED internal
  226.                                      ; buffer)
  227.       Mov    DS,CS                   ; make sure our data is from this segment
  228. ;
  229. ;  If we are not enqueued to CED then we merely call setup
  230. ;
  231.   NoCED:
  232.       Call SetUP                     ; Save current drive and path, reset drive
  233. ;
  234. ;  We begin by determining if there are any command line arguments.  If we
  235. ;  are enqueued to CED then we see if the first character in the buffer is a
  236. ;  carriage return.  If we are running from DOS then we look in the PSP for the
  237. ;  command line count.
  238. ;
  239.       Cmp    CEDFlag,1
  240.       Jne    Not_Enqueued_To_CED
  241. ;
  242. ;  Nothing but CR on command line? If so show path and leave
  243. ;
  244.   CED_CR_Check:
  245.       ES Mov AL,B [BP]               ; Any characters on the command line?
  246.       Inc    BP
  247.       Cmp    AL,' '
  248.       Je     CED_CR_Check
  249.       Cmp    AL,CR
  250.       Je     No_Parameters           ; no so go set to root and leave
  251.  
  252. ;
  253. ;  The first character wasn't a CR so let's find out how many characters
  254. ;  are on the command line and go process them.
  255. ;
  256.       Mov    CX,64                   ; assume 64 characters on command line
  257.       Mov    BX,CX                   ; save CX in BX
  258.       Mov    AL,CR                   ; want to find CR
  259.       Mov    DI,BP                   ; point DI to CED command line
  260.  
  261.       Repne  Scasb                   ; scan for CR
  262.       Jcxz   Too_Many_Characters
  263.  
  264.       Sub    BX,CX                   ; calculate number of chars on command line
  265.       Mov    CX,BX
  266.  
  267.       Jmp Short Got_Parameters       ; go process them
  268.  
  269.   Too_Many_Characters:
  270.  
  271.       Mov    Errlvl,2                ; signal error type (too many characters)
  272.       Jmp    Error_Found
  273. ;
  274. ;  If we are not enqueued to CED we get the number of chars from the PSP
  275. ;
  276.    Not_Enqueued_To_CED:
  277.  
  278.       Sub    CX,CX                   ; Clear CX
  279.       Mov    CL,B [080]              ; Get the number of characters on the
  280.                                      ; command line (from the PSP)
  281.  
  282.       Cmp    CX,64                   ; more than 64 characters not allowed
  283.       Ja     Too_Many_Characters
  284.  
  285.       Cmp    CX,0                    ; Anything on the command line?
  286.       Jne    Got_Parameters
  287. ;
  288. ;  If we find nothing then we show the current path and leave
  289. ;
  290.   No_Parameters:
  291.  
  292.       Call ShowPath                  ; set root dir and leave
  293.       Jmp    Exit
  294. ;
  295. ;  We have found some parameters so we processes them.
  296. ;
  297.   Got_Parameters:
  298.  
  299.       Call CommandLine
  300. ;
  301. ;  If the carry flag is set when we exit CommandLine we were unsuccessful
  302. ;
  303.       Jc     Error_Found
  304. ;
  305. ;  If Done_Flag is set then we were successful, we're finished and we can leave
  306. ;
  307.       Cmp    Done_Flag,1
  308.       If e Jmp Exit
  309. ;
  310. ;  If we return from CommandLine with CDFlag set that indicates that a
  311. ;  specific path has been selected and we switch to that specified path.
  312. ;  Otherwise we search for the desired subdirectory
  313. ;
  314.       Cmp    CDFlag,1
  315.       Jne    Look_For_The_Subdir
  316.  
  317.       Call SetPath
  318. ;
  319. ;  If the carry flag is set upon return from SetPath the path does not
  320. ;  exist and we display the not found message and return to the starting point
  321. ;  otherwise we're through and we can leave
  322. ;
  323.       If nc Jmp Short Exit
  324.       Mov    Errlvl,5                ; signal error type (invalid path)
  325.       Jmp Short Error_Found
  326. ;
  327. ;  Now if CDFlag was not set we must search for the subdir.  We will begin by
  328. ;  searching the current directory (like the CD command) and then, if required,
  329. ;  we'll search the rest of the disk.
  330. ;
  331.   Look_For_The_Subdir:
  332.  
  333.       Mov    OneDeepFlag,1           ; search current level
  334.       Call   GetDir                  ; Read the directory
  335. ;
  336. ;  Now, we reset OneDeepFlag just in case and see if we were successfull
  337. ;
  338.       Mov    OneDeepFlag,0           ; reset OneDeepFlag
  339.       Cmp    Done_Flag,1             ; did we find it?
  340.       Je     Exit                    ; found it so leave
  341. ;
  342. ;  If we were not successful searching the current directory then we search
  343. ;  more of the disk.  (if rootflag is set then we search the whole disk,
  344. ;  otherwise we search only the subordinate directories.
  345. ;
  346.       Cmp    RootFlag,1              ; default to the root directory?
  347.       If ne Call No_Arg              ; if not equal set to root for search
  348.       Call   GetDir                  ; Read the directory
  349. ;
  350. ;  If Done_Flag is set then we have been successful, otherwise we did not
  351. ;  find the desired subdirectory.
  352. ;
  353.       Cmp    Done_Flag,1
  354.       Je     Exit
  355.  
  356.       Mov    Errlvl,6                ; signal error type (subdir not found)
  357.       Jmp Short Error_Found
  358. ;
  359. ;  If we make it here we have not found the subdirectory so we tell the user
  360. ;  and return them to the starting drive:subdirectory.
  361. ;
  362.   Error_Found:
  363. ;
  364. ;  We begin by sending a message to the user
  365. ;
  366.       Xor    AX,AX                   ; clear AX
  367.       Mov    DX,Offset ErrorMsgs     ; point to the beginning of the error msgs
  368.       Mov    AL,Errlvl               ; which error?
  369.       Dec    AX                      ; decrement for position
  370.       Mov    CX,45                   ; characters per message
  371.       Mul    CL                      ; times error type-1
  372.       Add    DX,AX                   ; point to it
  373.       Call   PrintS
  374.  
  375. ;
  376. ;  Now we reset the drive if it has been changed.  NOTE: A Ctrl+Brk during
  377. ;  processing will come here and the user will be returned home (so to speak)
  378. ;
  379.   NFCB:
  380.       Sub    DX,DX                   ; clear DX
  381.       Mov    DL,OrigDr               ; get original drive
  382.       Cmp    DL,RootDir              ; compare with current drive
  383. ;
  384. ;  If the selected directory does not match the original directory reset
  385. ;
  386.       Je     Same_Drive
  387.  
  388.       Sub    DL,'A'                  ; change DL from ascii
  389.       Set_Drive                      ; Macro...
  390. ;
  391. ;  Now we reset to our original path and leave
  392. ;
  393.   Same_Drive:
  394.  
  395.       Change_Dir OrigDr              ; Set path to original path (Macro...)
  396.  
  397. Exit:
  398. ;
  399. ;  Now, if we are enqueued to CED we leave with a far return, otherwise
  400. ;  we exit with DOS function 4C.
  401. ;
  402.       Cmp     CEDFlag,1              ; enqueued to CED
  403.       Jne     ExitDOS
  404.  
  405.       Mov     RootFlag,0             ; reset flags for next time
  406.       Mov     CDFlag,0
  407.       Mov     OneDeepFlag,0
  408.       Mov     Done_Flag,0
  409.  
  410.       Mov     DtaPointer,offset DtaAreaBegin    ; reset pointer to our DTA
  411.  
  412.       Mov     ES,CS                  ; clear out start of DTA
  413.       Mov     DI,[DtaPointer]
  414.       Mov     AX,0
  415.       Mov     CX,43
  416.  
  417.    Dta_Clear:
  418.  
  419.       Stosw
  420.       loop    Dta_Clear
  421. ;
  422. ;  During the Setup procedure we took over the Ctrl-Break address
  423. ;  so now we restore it.
  424. ;
  425.       Mov     DX,CtrlBrkOff          ; Ctrl-Break offset
  426.       Mov     DS,CtrlBrkSeg          ; Ctrl-Break segment
  427.       Mov     AH,025                 ; set interrupt vector
  428.       Int     021
  429.  
  430.       RetF                           ; yes, exit with far return
  431.  
  432. ExitDOS:
  433.       Mov     AL,Errlvl              ; Return to system
  434.       Mov     AH,04C                 ; via EXIT
  435.       Int     021
  436.  
  437. ;---------------------------------------------------------------------------;
  438. ; No_Arg                                                                    ;
  439. ;                                                                           ;
  440. ;     No_Arg resets the current path to the root directory.                 ;
  441. ;                                                                           ;
  442. ;---------------------------------------------------------------------------;
  443.  
  444. No_Arg:
  445.                                      ; If no argument then set current
  446.       Change_Dir RootDir             ; path to root directory
  447.  
  448.       Ret
  449.  
  450. ;---------------------------------------------------------------------------;
  451. ; SetUp                                                                     ;
  452. ;                                                                           ;
  453. ;     SetUp initializes some variables and resets the disk drives           ;
  454. ;                                                                           ;
  455. ;---------------------------------------------------------------------------;
  456.  
  457. SetUp:
  458.       Push   DX,ES,DS
  459.  
  460. ;
  461. ;  We begin with a disk reset
  462. ;
  463.       Mov    AH,0D                   ; Reset diskettes
  464.       Int    021
  465. ;
  466. ;  Now we call DOS for the current disk drive and store the information
  467. ;  as an ascii drive specifier in several variables for future use
  468. ;
  469.       Current_Disk                   ; Get current disk  (Macro...)
  470.  
  471.       Add    AL,'A'
  472.       Mov    OrigDr,AL               ; Save original drive letter
  473.       Mov    RootDir,AL              ;
  474.       Mov    ScratchDirStart,AL
  475. ;
  476. ;  We also want to store our current path so we can return if necessary
  477.  
  478.       Mov    DL,OrigDr               ; put original drive in DL
  479.       Sub    DL,'@'                  ; convert from ascii character
  480.       Mov    SI,Offset OrigDir + 1   ; the original drive
  481.       Get_Path                       ; Macro...
  482. ;
  483. ;  Our last task is to point the Ctrl+Break vector to our Not_Found code
  484. ;  so the user is left where they began if using Ctrl+Break.  But first we
  485. ;  store the current Ctrl-Brk vector so we can restore it when we leave
  486. ;
  487.       Mov    AX,03523                ; call DOS for Ctrl-Break location
  488.       Int    021
  489.       Mov    CtrlBrkSeg,ES
  490.       Mov    CtrlBrkOff,BX
  491. ;
  492. ;  Now let's set up our Ctrl-Brk.
  493. ;
  494.       Mov    AX,02523                ; set Ctrl+Break vector to point
  495.       Mov    DX,Offset CtrlBrk       ; to our not found. This way a Ctrl+Brk
  496.       Int    021                     ; will leave us in the place we started
  497.  
  498.       Pop    DS,ES,DX
  499.       Ret
  500.  
  501. ;---------------------------------------------------------------------------;
  502. ; CommandLine                                                               ;
  503. ;                                                                           ;
  504. ;     CommandLine parses the command line, looking for switches and sub-    ;
  505. ;     dir names                                                             ;
  506. ;                                                                           ;
  507. ;---------------------------------------------------------------------------;
  508.  
  509. CommandLine:
  510. ;
  511. ;  We begin by setting DI and defaulting SI to the PSP
  512. ;
  513.       Mov    SI,081                  ; point SI to the beginning of the
  514.                                      ; command line
  515. ;
  516. ;  If we are Enqueued to CED then we want SI to point to BP-1.
  517. ;
  518.       Cmp    CEDFlag,1               ; enqueued to CED
  519.       Jne    Set_DI                  ; nope, go on
  520.       Dec    BP                      ; decrement BP
  521.       Mov    SI,BP                   ; mov BP to SI
  522. ;
  523. ;  Now setup DI
  524. ;
  525.   Set_DI:
  526.  
  527.       Mov    DI,Offset Sub_dir       ; point DI to our internal buffer for
  528.                                      ; the desired sub directory name
  529. ;
  530. ;  Now, we want to scan the command line to see if a drive was specified
  531. ;  We do this by looking for a ':' character. (remember cx holds the number
  532. ;  of parameters)
  533. ;
  534.       Push   DI                      ; save DI
  535.       Mov    DI,SI
  536.       Mov    al,':'                  ; we'll look for a ':'
  537.       Repne  Scasb
  538. ;
  539. ;  Just to be sure we found a character and not the end of the line we peek
  540. ;  at the position immediately before the current DI position
  541. ;
  542.       ES Cmp B [DI-1],':'            ; did we find one or are we at the end
  543.                                      ; of the command line? (the segment
  544.                                      ; override is needed if enqueued to CED)
  545.       Jne    Clean_Up                ; if we did not find a ':' the go on
  546. ;
  547. ;  If we did find a drive letter then we set SI to point to the char after ':'
  548. ;
  549.       Mov    SI,DI                   ; now, point SI to the character following
  550.                                      ; the ':' character
  551. ;
  552. ;  We now point DI to the drive letter and put it in AL
  553. ;
  554.       Sub    DI,2                    ; point DI to the drive specifier
  555.       ES Mov AL,B [DI]               ; save the drive specifier in al - again
  556.                                      ; the segment override is needed for CED)
  557. ;
  558. ;  We must check the drive letter to see that it is a letter and then make sure
  559. ;  it is capitalized
  560. ;
  561.       Cmp    AL,'A'                  ; compare with A
  562.       If b Jmp DriveError            ; if smaller then it is an erroneous drive
  563.  
  564.       Cmp    AL,'z'                  ; compare with z
  565.       If a Jmp DriveError            ; if larger then it is an erroneous drive
  566.  
  567.       Cmp    AL,'a'                  ; lowercase letter?
  568.       Jb     New_Drive?              ; no its upper case so lets go on
  569.       Xor    AL,020                  ; make upper case
  570. ;
  571. ;  Now we have an uppercase drive letter we first check to see that it is
  572. ;  different from the original drive if its not we go on.
  573. ;
  574.   New_Drive?:
  575.       Cmp    OrigDr,AL
  576.       Je     Anything_Else_On_CLine?
  577. ;
  578. ;  We have a different drive letter so lets store it and the change drives
  579. ;
  580.       Mov    RootDir,AL              ; save new drive specifier
  581.       Mov    ScratchDirStart,AL
  582. ;
  583. ;  After saving we call DOS and change the drive to the desired one
  584. ;
  585.       Sub    DX,DX                   ; clear dx
  586.       Mov    DL,AL                   ; must change drive to number, not ascii
  587.       Sub    DL,'A'
  588.       Set_Drive                      ; Macro....
  589. ;
  590. ;  To speed things up we look to see if there's anything but a CR on the
  591. ;  command line.
  592. ;
  593.   Anything_Else_On_CLine?:
  594.  
  595.       ES Cmp B [SI],' '              ; strip the spaces (ES override for CED)
  596.       Jne    Not_Blank               ; not a blank, how about a CR?
  597.       Inc    SI                      ; increment SI to check the next character
  598.  
  599.       Jmp Short Anything_Else_On_CLine?
  600.  
  601.   Not_Blank:
  602.  
  603.       ES Cmp B [SI],CR               ; found a CR?
  604.       Jne    Clean_Up                ; if not go on
  605.  
  606.       Mov    Done_Flag,1
  607.       Pop    DI                      ; get DI off stack
  608.       Jmp    ExitCL                  ; leave
  609.  
  610.   Clean_Up:
  611.  
  612.       Pop    DI                      ; get DI off stack
  613.  
  614. ;
  615. ;  We've now found a drive if it has been specified and we're ready
  616. ;  to look at the rest of the command line
  617. ;
  618.   Parse_Command_Line:
  619.  
  620.       Mov    DS,ES                   ; must play with segments incase enqueued
  621.                                      ; to CED
  622.       Lodsb                          ; get character from command line and
  623.                                      ; put it in al
  624.       Mov    DS,CS
  625.  
  626.       Cmp    AL,' '                  ; strip leading blanks from the command
  627.       Jz     Parse_Command_Line      ; line
  628.  
  629.       Cmp    AL,CR                   ; is it a carriage return ?
  630.       If e Jmp We_Are_Finished       ; if so we're at the end so jump on
  631. ;
  632. ;  We need to check and see if we are to be enqueued to CED
  633. ;
  634.       Cmp    AL,'['                  ; found enqueue command?
  635.       Jne    Back_One?               ; nope, go on
  636.  
  637.       Cmp    DI,Offset Sub_Dir       ; found it, is it the first character?
  638.       If e Jmp CEDEnqueue            ; yes then enqueue
  639.       Stc                            ; no, error so leave
  640.       Mov    Errlvl,3                ; signal error type (illegal character)
  641.       Jmp    ExitCL
  642. ;
  643. ;  If we find a '.' character we must check for '..' which CD uses
  644. ;  to go back one level
  645. ;
  646.   Back_One?:
  647.  
  648.       Cmp    AL,'.'
  649.       Jne    Display_Help?
  650. ;
  651. ;  We found one '.' but are there two?
  652. ;
  653.       ES Cmp W [SI-1],'..'           ; two periods?
  654.       Je     Go_Back_One             ; if so back one dir.
  655.       Stc                            ; if not error
  656.       Mov    Errlvl,3                ; signal error type (illegal character)
  657.       Jmp    ExitCL
  658.  
  659.   Go_Back_One:
  660.  
  661.       Change_Dir BackOneDir          ; change back one
  662.       Jnc    Go_Back_One_Worked
  663.       Mov    Errlvl,4                ; signal error type (in root)
  664.       Jmp    ExitCL                  ; leave
  665.  
  666.   Go_Back_One_Worked:
  667.  
  668.       Mov    Done_Flag,1             ; else set done_flag and leave
  669.       Jmp    ExitCL                  ; do a not so nice jump to exit
  670. ;
  671. ;  If the help character (?) is the first character on the command line
  672. ;  then we display the help message and leave
  673. ;
  674.   Display_Help?:
  675.  
  676.       Cmp    AL,'?'                  ; help character?
  677.       Jne    Search_Below?
  678.  
  679.       Cmp    DI,Offset Sub_Dir       ; is it the first character ?
  680.       Jne    Search_Below?
  681. ;
  682. ;  Now that we have found the help character is help available?
  683. ;
  684.       Cmp    HelpFlag,1              ; help info loaded ?
  685.       Je     Show_Help               ; yes so display it
  686. ;
  687. ;  Help not available, display message.
  688. ;
  689.       Mov    DX,Offset NoHelp        ; display error message and leave
  690.       Call PrintS
  691.       Mov    Done_Flag,1
  692.       Jmp    ExitCL
  693.  
  694.   Show_Help:
  695.  
  696.       Mov    DX,Offset Help          ; yes, let's display the help screen and
  697.       Call PrintS                    ; then leave
  698.       Mov    Done_Flag,1
  699.       Jmp    ExitCL
  700. ;
  701. ;  The / switch indicates that we are only to search for subdirectories of
  702. ;  the current directory. (This was changed in version 3.0 of SD)
  703. ;
  704.  
  705.   Search_Below?:
  706.  
  707.       Cmp    AL,'/'                  ;search below (/) switch ?
  708.       If ne Jmp Path_Specified?
  709. ;
  710. ;  If we find this character we want to know if its the first character of the
  711. ;  command line or not.
  712. ;
  713.       Cmp    DI,Offset Sub_Dir       ; have we stored any characters yet?
  714.       Jne    SB_Not_First_Char
  715. ;
  716. ;  If it is the first we set a flag to keep us from defaulting to the
  717. ;  root directory before we search
  718. ;
  719.       Mov RootFlag,1                 ; signal to search below, not reset to
  720.       Jmp Short Parse_Command_Line   ; root
  721. ;
  722. ;  Now, if its not the first character on the command line we need to
  723. ;  do some fancy footwork.  First we need to see if a specific path
  724. ;  has previously been signaled.
  725. ;
  726.   SB_Not_First_Char:
  727.  
  728.       Cmp    CDFlag,1                ; have we already seen a specific
  729.                                      ; path on the command line?
  730.       Jne    SB_No_Path_Yet          ; no so go on
  731. ;
  732. ;  A specific path has been previously selected so we make this path an
  733. ;  asciiz string and switch to it.  Upon completion we reset DI to the
  734. ;  begining of our command line buffer and clear the specific subdir flag.
  735. ;
  736.       Mov    B [DI],0                ; make current path asciiz string
  737.       Call SetPath                   ; change to the already specified path
  738. ;
  739. ;  If the carry flag is set there was an error in the path (usually it didn't
  740. ;  exist)
  741. ;
  742.       Jnc    SB_Not_First_Char_Done  ; if the subdir doesn't exist leave
  743.       Mov    Errlvl,5                ; signal error type (invalid path)
  744.       Jmp    ExitCL                  ; leave
  745. ;
  746. ;  If the path existed then we reset DI to the beginning of our buffer,
  747. ;  reset CDFlag and set RootFlag.
  748. ;
  749.   SB_Not_First_Char_Done:
  750.  
  751.       Mov    DI,Offset Sub_Dir       ; reset DI
  752.       Mov    CDFlag,0                ; clear specific subdir flag
  753.       Mov    RootFlag,1              ; search below, don't default to root
  754.       Jmp Short Parse_Command_Line   ; go get next char
  755. ;
  756. ;  It hasn't so this means that we search the disk for the subdir specified
  757. ;  up till now (on the command line).  To do this we must make the name an
  758. ;  asciiz string, search for it then specify that we don't want to default
  759. ;  to the root directory before out next search. DI must also be reset.
  760. ;  In doing the search we imitate the CD command by first searching the current
  761. ;  level and then enhance it by searching the whole disk (if RootFlag set,
  762. ;  otherwise search only below current dir)
  763. ;
  764.    SB_No_Path_Yet:
  765.  
  766.       Mov    B [DI],0                ; make current path asciiz string
  767.       Mov    Count,DI                ; how many characters stored?
  768.       Sub    Count,Offset Sub_Dir    ; we need to set this for GetDir
  769. ;
  770. ;  Set OneDeepFlag so we only check current directory
  771. ;
  772.       Mov    OneDeepFlag,1           ; start by searching current level
  773.       Call GetDir                    ; search for path already specified
  774. ;
  775. ;  Reset OneDeepFlag, check to see if we are done and if so move on
  776. ;
  777.       Mov    OneDeepFlag,0           ; reset the OneDeepFlag
  778.       Cmp    Done_Flag,1             ; see if we were successful
  779.       Je     Search_A_Success        ; if not leave
  780. ;
  781. ;  ..otherwise re-search.  We reset to the root directory if RootFlag is set
  782. ;
  783.       Cmp    RootFlag,1              ; searching only below?
  784.       If ne Call No_Arg              ; set to root for search
  785.       Mov    Count,DI                ; how many characters stored?
  786.       Sub    Count,Offset Sub_Dir    ; we need to set this for GetDir
  787.       Call GetDir                    ; search for path already specified
  788. ;
  789. ;  If Done_Flag is set then we have found our directory, otherwise we set
  790. ;  the carry flag and leave
  791. ;
  792.       Cmp    Done_Flag,1             ; see if we were successful
  793.       Je     Search_A_Success        ; if not leave
  794.       Stc
  795.       Mov    Errlvl,6                ; signal error type (subdir not found)
  796.       Jmp    ExitCL
  797. ;
  798. ;  We found the subdir, now reset Done_Flag for future use as well as DI
  799. ;
  800.    Search_A_Success:
  801.  
  802.       Mov    Done_Flag,0             ; reset Done_Flag incase of future searches
  803.       Mov    RootFlag,1              ; search below, don't default to root
  804.       Mov    DI,Offset Sub_Dir       ; reset DI
  805.       Jmp Short Parse_Command_Line
  806. ;
  807. ;  The \ switch indicates a specific path is specified. (i.e. no searching
  808. ;  just switch to this path.
  809. ;
  810.   Path_Specified?:
  811.  
  812.       Cmp    AL,'\'                  ; Path seperator/indicator (\) ?
  813.       If ne Jmp Process_Character
  814. ;
  815. ;  If we find this flag we want to know if its the first character of the
  816. ;  command line or not.
  817. ;
  818.       Cmp    DI,Offset Sub_Dir       ; still pointing to beginning?
  819.       Jne    PS_Not_First_Char
  820. ;
  821. ;  If it is the first we set a flag to indicate a specific subdir has been
  822. ;  selected.
  823. ;
  824.       Change_Dir RootDir             ; make sure we are at the root dir
  825.       Mov    CDFlag,1                ; set flag to select specific subdir
  826. ;
  827. ;  Strip any leading blanks.....
  828. ;
  829.    P1:
  830.       ES Cmp B [SI],' '              ; strip any blanks
  831.       Jne    P2
  832.       Inc    SI
  833.       Jmp Short P1
  834. ;
  835. ;  If all that's left is a carriage return we are done, otherwise get the next.
  836. ;
  837.    P2:
  838.       ES Cmp B [SI],CR
  839.       If ne Jmp Short Parse_Command_Line
  840.       Mov    Done_Flag,1
  841.       Jmp    ExitCL
  842. ;
  843. ;  If its not the first character we check to see if another one has already
  844. ;  been found.
  845. ;
  846.   PS_Not_First_Char:
  847.  
  848.       Cmp    CDFlag,1                ; already set to look for path?
  849.       Je     Already_Reading_Path    ; yes so go on
  850. ;
  851. ;  None has been found yet so we make the current string (in the buffer)
  852. ;  an asciiz string and go search for the subdir it specifies.  After
  853. ;  the search we reset DI, Done_Flag and CDFlag.
  854. ;
  855.       Mov    B [DI],0                ; make string asciiz
  856. ;
  857. ;  Set the character count and a flag to search the current level
  858. ;
  859.  
  860.       Mov    Count,DI                ; how many characters stored?
  861.       Sub    Count,Offset Sub_Dir    ; we need to set this for GetDir
  862.       Mov    OneDeepFlag,1           ; start by searching current level
  863.       Call GetDir                    ; search for path already specified
  864. ;
  865. ;  Reset the OneDeepFlag and see if we found our subdir
  866. ;
  867.       Mov    OneDeepFlag,0           ; reset the OneDeepFlag
  868.       Cmp    Done_Flag,1             ; see if we were successful
  869.       Je     PS_Search_A_Success     ; if not leave
  870. ;
  871. ;  If we didn't find the dir we check to see if we reset to the root and
  872. ;  continue on with the search.
  873. ;
  874.       Cmp    RootFlag,1              ; reseting to root ?
  875.       If ne Call No_Arg              ; set to root for search if flag not set
  876.  
  877.       Mov    Count,DI                ; how many characters stored?
  878.       Sub    Count,Offset Sub_Dir    ; we need to set this for GetDir
  879.       Call GetDir                    ; search for specified path
  880. ;
  881. ;  We have searched the desired part of the drive, now did we find anything?
  882. ;
  883.       Cmp    Done_Flag,1             ; see if we were successful
  884. ;
  885. ;  If we did we reset the flags and continue on, otherwise leave.
  886. ;
  887.       Je     PS_Search_A_Success     ; if not leave
  888.       Stc                            ; set carry flag to signal error
  889.       Mov    Errlvl,6                ; signal error type (subdir not found)
  890.       Jmp Short ExitCL
  891.  
  892.   PS_Search_A_Success:
  893.  
  894.       Mov    Done_Flag,0             ; reset Done_Flag incase of future searches
  895.       Mov    DI,Offset Sub_Dir       ; reset DI
  896.       Mov    CDFlag,1                ; indicate specific path
  897.       Jmp    Short Parse_Command_Line
  898. ;
  899. ;  If we have already seen a path seperator we continue building the
  900. ;  desired path in our buffer.
  901. ;
  902.   Already_Reading_Path:
  903.  
  904.       Push   ES                      ; change segment registers.  This is
  905.       Mov    ES,CS                   ; required if we are enqueued to CED
  906.       Stosb
  907.       Pop    ES
  908.       Jmp Short Parse_Command_Line   ; and get next char
  909. ;
  910. ;  Now we make sure the character is upper case because DOS doesn't like
  911. ;  lower case.  There is potential for error here because these checks will
  912. ;  pass some invalid characters (for DOS filenames).  The result is some
  913. ;  delay before an error is found.
  914. ;
  915.   Process_Character:
  916.  
  917.       Cmp    AL,'!'                  ; compare with !
  918.       If b Jmp Parse_Command_Line    ; get next char if smaller
  919.  
  920.       Cmp    AL,'z'                  ; compare with z
  921.       If a Jmp Parse_Command_Line    ; get next char if bigger
  922.  
  923.       Cmp    AL,'a'                  ; lowercase letter?
  924.       Jb     Store_The_Character     ; nope so go on
  925.       Xor    AL,020                  ; make upper case
  926. ;
  927. ;  Now we have an upper case character let's store it in our buffer and
  928. ;  go get the next
  929. ;
  930.   Store_The_Character:
  931.  
  932.       Push   ES                      ; again, we have to change the segment
  933.       Mov    ES,CS                   ; registers to allow for CED
  934.       Stosb
  935.       Pop    ES
  936.  
  937.       Jmp Short Parse_Command_Line
  938. ;
  939. ;  When we get here we're done with the command line and we must make
  940. ;  sure that we have an asciiz name in our buffer.
  941. ;
  942.   We_Are_Finished:
  943.  
  944.       Mov    Count,DI                ; how many characters stored?
  945.       Sub    Count,Offset Sub_Dir
  946. ;
  947. ;  If count is zero we have not found anything on the command line so let's
  948. ;  reset to the root directory and leave
  949. ;
  950.       Cmp    Count,0
  951.       Jne    Something_In_Buffer
  952. ;
  953. ;  Show the path
  954. ;
  955.       Call ShowPath                  ; display the path
  956.       Mov    Done_Flag,1             ; signal done
  957.       Jmp Short ExitCL               ; leave
  958. ;
  959. ;  We found something so let's make sure its an asciiz string
  960. ;
  961.   Something_In_Buffer:
  962.  
  963.       Mov    AL,0
  964.       Push   ES                      ; override the segment registers
  965.       Mov    ES,CS
  966.       Stosb
  967.       Pop    ES
  968.       Jmp Short ExitCL
  969. ;
  970. ;  If an illegal drive was specified on the command line we come here and
  971. ;  display and error message.  The Done_Flag is then set and we return to
  972. ;  the main program.
  973. ;
  974.   DriveError:                        ; we come here if the drive specifier
  975.                                      ; is not in A to z
  976.       Pop    DI
  977.       Mov    Errlvl,1
  978.       Stc
  979.  
  980. ExitCL:
  981.       Ret
  982.  
  983. ;---------------------------------------------------------------------------;
  984. ; GetDir                                                                    ;
  985. ;                                                                           ;
  986. ;     GetDir searches for the desired subdirectory.  The extent of the      ;
  987. ;     search can be modified by command line switches                       ;
  988. ;                                                                           ;
  989. ;  Based on WHISK by Charles Wooster                                        ;
  990. ;---------------------------------------------------------------------------;
  991.  
  992. GetDir:
  993.           Push    SI,DI,ES
  994.           Mov     ES,CS
  995.  
  996.           Mov     Done_Flag,0
  997.  
  998. ;     Find first or next subdirectory level
  999. ;     -------------------------------------
  1000.  
  1001. NextLevel:
  1002.           Mov     DX,[DTAPointer]      ; Next nested DTA
  1003.           Mov     AH,1Ah               ; For DOS call to set DTA
  1004.           Int     21h                  ; Do it
  1005.  
  1006.           Cmp     [Direction],0        ; Check if we're nesting
  1007.           Jnz     FindNextFile         ; If not, we're continuing
  1008.  
  1009.           Mov     DX,Offset SearchAsciiZ     ; We search for *.*
  1010.           Mov     CX,10h               ; Subdirectory attribute
  1011.           Mov     AH,4Eh               ; Find first file
  1012.           Int     21h                  ;   by calling DOS
  1013.  
  1014.           Jmp     Short TestMatch      ; Hop around next section
  1015. FindNextFile:
  1016.           Mov     AH,4Fh               ; Find next file
  1017.           Int     21h                  ;   by calling DOS
  1018. TestMatch:
  1019.           Jc      NoMoreFiles          ; If CY flag, at end of rope
  1020.  
  1021.           Mov     BX,[DTAPointer]      ; Our find stuff is here
  1022.           Test    B [BX + 21],10h      ; Test if directory attribute
  1023.           Jz      FindNextFile         ; If not, continue search
  1024.  
  1025.           Add     BX,30                ; Now points to directory name
  1026.           Cmp     Byte Ptr [BX],'.'    ; Ignore "." and ".." entries
  1027.           Jz      FindNextFile         ;   by continuing the search
  1028.  
  1029.           Cmp     OneDeepFlag,1        ; looking only at this level?
  1030.           Je      Compare
  1031.  
  1032.           Push    BX                   ; save pointer to subdir name
  1033.  
  1034.           Mov     DX,BX                ; Now DX points to found dir
  1035.           Mov     AH,3Bh               ; Set up DOS function call
  1036.           Int     21h                  ; And change directory
  1037.  
  1038.           Pop     BX                   ; get pointer to subdir name back
  1039.     Compare:
  1040.           Sub     CX,CX
  1041.           Mov     CX,Count
  1042.           Mov     DI, Offset Sub_Dir
  1043.           Lea     SI, BX
  1044.           Repe    Cmpsb
  1045.  
  1046.           Jz      Found                ; matched up so leave
  1047.  
  1048.           Cmp     OneDeepFlag,1
  1049.           Jne     GoOn
  1050.           Mov     [Direction],-1
  1051.           Jmp Short NextLevel
  1052.       GoOn:
  1053.           Add     [DtaPointer],43      ; New DTA for new level
  1054.           Mov     [Direction],0        ; I.E., Find first file
  1055.  
  1056.           Jmp     NextLevel            ; All ready to cycle through
  1057.  
  1058. ;     No More Files Found -- go back to previous level
  1059. ;     ------------------------------------------------
  1060.  
  1061. NoMoreFiles:
  1062.           Cmp     [DTAPointer],Offset DtaAreaBegin   ; See if back at start
  1063.  
  1064.           Jz      ExitGD               ; If so, that's all, folks
  1065.  
  1066.           Sub     [DTAPointer],43      ; Back one for previous
  1067.           Mov     [Direction],-1       ; I.E., will find next file
  1068.  
  1069.           Mov     DX,Offset BackOneDir ; The string ".."
  1070.           Mov     AH,3Bh               ; Call to change directory
  1071.           Int     21h                  ; Change directory to father
  1072.  
  1073.           Jmp     NextLevel            ; And continue the search
  1074. Found:
  1075.           Cmp     OneDeepFlag,1
  1076.           If ne Jmp Short F1
  1077.  
  1078.           Mov     DX,BX                ; Now DX points to found dir
  1079.           Mov     AH,3Bh               ; Set up DOS function call
  1080.           Int     21h                  ; And change directory
  1081.       F1:
  1082.           Mov     Done_Flag,1
  1083. ExitGD:
  1084.           Mov     [Direction],0
  1085.           Pop     ES,DI,SI
  1086.           Ret
  1087.  
  1088. ;---------------------------------------------------------------------------;
  1089. ; SetPath                                                                   ;
  1090. ;                                                                          ;
  1091. ;     SetPath changes to the designated path. It first checks the current  ;
  1092. ;     path and if its not the root directory, appends the desired path to   ;
  1093. ;     this directory                                                        ;
  1094. ;                                                                           ;
  1095. ;---------------------------------------------------------------------------;
  1096.  
  1097. SetPath:
  1098. ;
  1099. ;  We begin by saving SI, DI and ES.  Then we point ES to CS for the Scasb
  1100. ;  and the Stosb.  This is required in case we are enqueued to CED.
  1101. ;
  1102.       Push   SI,DI,ES
  1103.       Mov    ES,CS
  1104.       Clc
  1105. ;
  1106. ;  Our first step is to call DOS for the current path to see if we are in
  1107. ;  the root directory or not.
  1108. ;
  1109.       Mov    DL,RootDir                ; check current drive
  1110.       Sub    DL,'@'                    ; change from ascii
  1111.       Mov    SI,Offset ScratchDir      ; scratch buffer for path
  1112.       Get_Path                         ; Macro...
  1113. ;
  1114. ;  If we are in the root directory (the first character in ScratchDir is an
  1115. ;  ascii null) then we can go on because Sub_Dir contains a complete path
  1116. ;
  1117.  
  1118.       Cmp    ScratchDir,0
  1119.       Je     SP1
  1120. ;
  1121. ;  If we are not in the root directory we must append the desired subdirectory
  1122. ;  to the end of the current directory before trying to select it.
  1123. ;
  1124.       Mov    CX,64
  1125.       Mov    DI,Offset ScratchDir      ; we want to find the
  1126.       Mov    AL,0                      ; end of the pathname
  1127.       Repne  Scasb
  1128.       Mov    AL,'\'                    ; insert path seperator at the end
  1129.       Dec    DI
  1130.       Stosb
  1131.       Mov    SI,Offset Sub_Dir
  1132. ;
  1133. ;  We now move the desired subdirectory to the end of the current subdir.
  1134. ;
  1135.   SP2:
  1136.       Lodsb
  1137.       Cmp    AL,0
  1138.       Je     ExitSetP
  1139.       Stosb
  1140.       Jmp Short SP2
  1141. ;
  1142. ;  If Sub_dir contains a complete path we move it to ScratchDir
  1143. ;
  1144.   SP1:
  1145.       Mov    DI,Offset ScratchDir      ; target
  1146.       Mov    SI,Offset Sub_Dir         ; sub dir from command line
  1147.   SP3:
  1148.       Lodsb
  1149.       Cmp    AL,0                      ; At the end yet ?
  1150.       Je     ExitSetP                  ; yes, gon on
  1151.       Stosb
  1152.       Jmp Short SP3
  1153.  
  1154. ExitSetP:
  1155. ;
  1156. ;  We store the null character in AL to insure an asciiz string and set
  1157. ;  the path.
  1158. ;
  1159.       Stosb                            ; store 0 to make asciiz string
  1160.  
  1161.       Change_Dir ScratchDirStart       ; Macro...
  1162.  
  1163.       Pop    ES,DI,SI
  1164.       Ret
  1165.  
  1166. ;---------------------------------------------------------------------------;
  1167. ; ShowPath                                                                  ;
  1168. ;                                                                          ;
  1169. ;     ShowPath displays the current path.                                   ;
  1170. ;                                                                           ;
  1171. ;---------------------------------------------------------------------------;
  1172.  
  1173. ShowPath:
  1174. ;
  1175. ;  We begin by saving SI, DI and ES.  Then we point ES to CS for the Scasb
  1176. ;  and the Stosb incase we are enqueued to CED.
  1177. ;
  1178.       Push   SI,DI,ES
  1179.       Mov    ES,CS
  1180. ;
  1181. ;  Our first step is to call DOS for the current path
  1182. ;
  1183.       Mov    DL,RootDir
  1184.       Sub    DL,'@'
  1185.       Mov    SI,Offset ScratchDir
  1186.       Get_Path
  1187. ;
  1188. ;  Now we display the path
  1189. ;
  1190.       Mov    SI,Offset ScratchDirStart
  1191.   SPath1:
  1192.       Lodsb
  1193.       Cmp    AL,0
  1194.       Je     ExitShowP
  1195.       Mov    DL,AL
  1196.       Mov    AH,06
  1197.       Int    021
  1198.       Jmp Short SPath1
  1199.  
  1200. ExitShowP:
  1201.       Mov    DL,CR                   ; print CRLF sequence
  1202.       Mov    AH,06
  1203.       Int    021
  1204.       Mov    DL,LF
  1205.       Mov    AH,06
  1206.       Int    021
  1207.  
  1208.  
  1209.       Pop    ES,DI,SI
  1210.       Ret
  1211.  
  1212. ;---------------------------------------------------------------------------;
  1213. ;                                                                           ;
  1214. ;     Print String like INT 21H function 9                                  ;
  1215. ;                                                                           ;
  1216. ;  written by V. Buerg                                                      ;
  1217. ;                                                                           ;
  1218. ;---------------------------------------------------------------------------;
  1219.  
  1220.  
  1221. PrintS:                                      ; DX has offset to string
  1222.       Push   SI                      ;  ending in char x'FF'
  1223.       Push   BX
  1224.       Push   CX
  1225.       Mov    SI,DX                   ; Ptr to string text
  1226.       Sub    CX,CX                   ; Overall text length
  1227. PS1:  Lodsb
  1228.       Cmp    AL,Stopper              ; Ending hex FF?
  1229.       Je     PS9
  1230.       Inc    CX
  1231.       Jmp    Short PS1
  1232.  
  1233. PS9:
  1234.       Mov    BX,1                    ; Standard output device
  1235.       Mov    AH,40h                  ;  to write to
  1236.       Int    21h
  1237.  
  1238.       Pop    CX                      ; Recover registers
  1239.       Pop    BX
  1240.       Pop    SI
  1241.       Ret
  1242.  
  1243. ;---------------------------------------------------------------------------;
  1244. ; CtrlBrk                                                                   ;
  1245. ;                                                                           ;
  1246. ;     CtrlBrk handles Ctrl-Breaks.  It calls a section of the code to       ;
  1247. ;     restore the original drive and path and leaves.                       ;
  1248. ;                                                                           ;
  1249. ;---------------------------------------------------------------------------;
  1250.  
  1251. CtrlBrk:
  1252.       Sti
  1253.       Push   AX,BX,CX,DX,SI,DI,ES,DS
  1254.  
  1255.       Sub    DX,DX                   ; clear DX
  1256.       Mov    DL,OrigDr               ; get original drive
  1257.       Cmp    DL,RootDir              ; compare with current drive
  1258. ;
  1259. ;  If the selected directory does not match the original directory reset
  1260. ;
  1261.       Je     Same_Drv
  1262.  
  1263.       Sub    DL,'A'                  ; change DL from ascii
  1264.       Set_Drive                      ; Macro...
  1265. ;
  1266. ;  Now we reset to our original path and leave
  1267. ;
  1268.   Same_Drv:
  1269.  
  1270.       Change_Dir OrigDr              ; Set path to original path (Macro...)
  1271.  
  1272.       Pop    DS,ES,DI,SI,DX,CX,BX,AX
  1273.       Stc
  1274.       RetF
  1275.  
  1276. ;----------------------------------------------------------------------------
  1277. ;
  1278. ;   This is where we will store the temporary directory information
  1279. ;
  1280.  
  1281.  
  1282. DtaAreaBegin   equ     $
  1283. DtaAreaEnd     equ     DtaAreaBegin + 10 * 43     ; Can have 10 DTAs of 43 bytes
  1284.  
  1285. ;
  1286. ;  Put the help here so that can be or not be part of memory resident code
  1287. ;  depending on user input.
  1288. ;
  1289.  
  1290.               Org DtaAreaEnd
  1291.  
  1292. Help           Db  CR,LF,'Usage:',CR,LF,CR,LF
  1293.                Db  '[d:\....]>SD [drive][command specification]',CR,LF
  1294.                Db  '      [drive] - the drive to search. (if not searching the current drive)',CR,LF,CR,LF
  1295.                Db  '      [command specification]',CR,LF,CR,LF
  1296.                Db  '              - this can be any valid CD command or any combination of \ (for',CR,LF
  1297.                Db  '                specific paths) or / (for search below the current dir)',CR,LF
  1298.                Db  '                (if blank SD returns the current path).',CR,LF,CR,LF
  1299.                Db  'A valid command could be:',CR,LF,CR,LF
  1300.                Db  '         SD c:\turbo/source\myprog',CR,LF,CR,LF
  1301.                Db  '         This would switch to c:\turbo then search its subdirectories for',CR,LF
  1302.                Db  '         a source subdirectory then switch to the myprog subdirectory.',CR,LF
  1303.                Db  '         If no \ or / is specified then the entire disk is searched for the',CR,LF
  1304.                Db  '         desired subdirectory starting with the current directory.',CR,LF,CR,LF
  1305.                Db  'Special Command:  SD [c will enqueue SD to the CED program (p for PCED)',CR,LF
  1306.                Db  '                  SD [c+ will enqueue SD without online help.',CR,LF,Stopper
  1307.  
  1308. ProgramEndH    Equ $
  1309.  
  1310. ;---------------------------------------------------------------------------;
  1311. ; CEDEnqueue                                                                ;
  1312. ;                                                                           ;
  1313. ;     CEDEnqueue enqueues SD to CED.  This code will be overwritten by      ;
  1314. ;     the Data in the DTAs.                                                 ;
  1315. ;                                                                           ;
  1316. ;---------------------------------------------------------------------------;
  1317.  
  1318. CommandString  db 'sd',CR,6 dup(0)
  1319.  
  1320. PErrorMSG       db 'Problem enqueueing to PCED.  Is it there ?',CR,LF,Stopper
  1321.  
  1322. CErrorMSG       db 'Problem enqueueing to CED.  Is it there ?',CR,LF,Stopper
  1323.  
  1324. CEDEnqueue:
  1325.  
  1326.       Mov    CEDFlag,1               ; set flag to signal enqueued to CED
  1327.  
  1328.       ES Cmp B [SI+1],'+'            ; storing help or not ?
  1329.       If e Mov HelpFlag,0            ; if '+' found no help
  1330.  
  1331.       ES Cmp B [SI],'c'              ; enqueue to CED ?
  1332.       Je     CED                     ; yes, so go on
  1333.  
  1334.       Call   FindCED                 ; find PCED interrupt
  1335.  
  1336.       Cmp    AL,2                    ; if al > 2 then PCED installed and al
  1337.       Jg     ItsOK                   ; contains interrupt to call
  1338.  
  1339.       Mov    DX,Offset PErrorMSG     ; point to the error msgs
  1340.       Call   PrintS
  1341.  
  1342.       Mov    Errlvl,7
  1343.       Jmp    ExitDOS
  1344.  
  1345. ItsOK:
  1346.       Call   PCEDEnqueue
  1347.       Jmp Short Envi
  1348. ;
  1349. ;  We now call CED to enqueue ourselves
  1350. ;
  1351. CED:
  1352.       Mov    AH,0FF                  ; CED services
  1353.       Mov    AL,0                    ; enqueue
  1354.       Mov    BL,1                    ; call us only from the DOS command line
  1355.       Mov    SI,offset CommandString
  1356.       Mov    DI,offset Start
  1357.       Int    021
  1358.  
  1359.       Cmp    AH,0FF
  1360.       Jne    Envi
  1361.  
  1362.       Mov    DX,Offset CErrorMSG     ; point to the error msgs
  1363.       Call   PrintS
  1364.  
  1365.       Mov    Errlvl,8
  1366.       Jmp    ExitDOS
  1367. ;
  1368. ;  Now we deallocate our environment block and free it up for other programs
  1369. ;
  1370. Envi:
  1371.       Mov    AH,049                  ; release memory call to DOS
  1372.       Mov    ES,[02C]                ; set ES to environment
  1373.       Int    021                     ; call DOS
  1374. ;
  1375. ;  Based on the variable HelpFlag we determine how much memory to
  1376. ;  allocate and TSR.  We will begin by assuming help will be installed
  1377. ;
  1378.       Mov    DX,ProgramEndH          ; set DX to include help
  1379.       Cmp    HelpFlag,1              ; are we supposed to include help?
  1380.       If ne Mov DX,DtaAreaEnd        ; if not change DX
  1381.  
  1382.       Int    027                     ; terminate and stay resident
  1383.  
  1384.  
  1385. ;---------------------------------------------------------------------------;
  1386. ; PCEDEnqueue                                                               ;
  1387. ;                                                                           ;
  1388. ;     PCEDEnqueue is called by CEDEnqueue when PCED is installed.  Its      ;
  1389. ;     purpose is to allow PCED to be attached to any system interrupt.      ;
  1390. ;     (It defaults to INT 61h                                               ;
  1391. ;                                                                           ;
  1392. ;---------------------------------------------------------------------------;
  1393.  
  1394.       PCED    label dword
  1395.       PCED_IP dw ?
  1396.       PCED_CS dw ?
  1397.  
  1398. PCEDEnqueue:
  1399.  
  1400.       Mov    AH,035     ; DOS get-vector fn
  1401.       Push   ES
  1402.       Int    021        ; Get vector to ES:BX
  1403.       Mov    PCED_IP,BX
  1404.       Mov    PCED_CS,ES
  1405.       Pop    ES
  1406.  
  1407.       Mov    AH,0                    ; enqueue
  1408.       Mov    AL,1                    ; call us only from the DOS command line
  1409.       Mov    SI,offset CommandString
  1410.       Mov    DI,offset Start
  1411.  
  1412.       Pushf            ; Needed for IRET
  1413.       Call   PCED      ; Execute PCED
  1414.  
  1415.       Ret
  1416.  
  1417. ; -------------------------------------------------------------
  1418. ; This procedure searches the environment for the currently
  1419. ; installed PCED and returns an appropriate result.
  1420. ;
  1421. ;    Written by Christopher J. Dunford (provided with
  1422. ;    PCED package)
  1423. ;
  1424. ;
  1425. ; The procedure is designed to be used as an include file.  To use
  1426. ; it, just INCLUDE this file in your program (or merge it in, if you
  1427. ; wish) and execute a CALL to 'FindCED'.
  1428. ;
  1429. ; Entry assumption:
  1430. ;    ES points to the program's PSP (which it will if you are creating
  1431. ;    a standard COM or EXE program and ES contains its original value
  1432. ;    from startup).
  1433. ;
  1434. ; Exit:
  1435. ;    AL == 0:  PCED not installed
  1436. ;    AL == 1:  CEDINT string in environment was invalid
  1437. ;    AL == 2:  Program at PCED interrupt vector ain't PCED
  1438. ;    AL == anything else is the PCED interrupt
  1439. ;    Other registers preserved
  1440. ;
  1441. ; NOTE 1: This routine was written without using any constants
  1442. ; or other good programming stuff so that it can simply be
  1443. ; included or merged into other programs intact, without
  1444. ; needing any header files, etc.
  1445. ;
  1446. ; NOTE 2: All labels declared in this procedure begin with 'SSG'
  1447. ; to minimize collisions with your own labels.
  1448. ; -------------------------------------------------------------
  1449.  
  1450. CEDINT$ db 'CEDINT='                    ; String to search for in env
  1451.  
  1452. FindCED:
  1453.  
  1454.         push bx
  1455.         push cx
  1456.         push dx
  1457.         push si
  1458.         push di
  1459.         push ds
  1460.  
  1461.         mov dx,es                       ; Save ES
  1462.         mov ax,cs                       ; Point DS to code segment
  1463.         mov ds,ax
  1464.  
  1465.         mov es,es:[2CH]                 ; ES = environment segment
  1466.         xor di,di                       ; Point to start of env in ES:DI
  1467.         cld
  1468.  
  1469. ; ----- Loop thru environment strings one by one, beginning here
  1470. SSG1:
  1471.         test byte ptr es:[di],-1        ; End of environment?
  1472.         jnz SSG1A                       ; Nope, continue
  1473.         mov al,61H                      ; Yes, use default interrupt
  1474.         jmp short SSG3
  1475.  
  1476. ; ----- Compare current env string to 'CEDINT='
  1477. SSG1A:
  1478.         mov si,offset CEDINT$           ; Point to 'CEDINT=' string
  1479.         mov bx,di                       ; Save ptr to start of env string
  1480.         mov cx,7                        ; Length of 'CEDINT='
  1481.         repe cmpsb                      ; Compare
  1482.         je SSG2                         ; Found it!
  1483.  
  1484.         mov di,bx                       ; Restore ptr to start of env string
  1485.         xor al,al                       ; Scan for end of string
  1486.         mov cx,-1
  1487.         repne scasb
  1488.         jmp SSG1                        ; Go back for next string
  1489.  
  1490. ; ----- Found it.  Get the interrupt number
  1491. SSG2:
  1492.         mov ax,es:[di]                  ; AX = int # (AL=hi byte)
  1493.         cmp byte ptr es:2[di],0         ; Should be 0 after int #
  1494.         jne SSG2A                       ; Oops
  1495.  
  1496.         call SSGX                       ; Convert AL from ASCII to binary
  1497.         jc SSG2A                        ; Error if carry
  1498.         mov cl,4                        ; Mov to high nibble
  1499.         shl al,cl
  1500.         xchg ah,al                      ; Put low byte in AL
  1501.         call SSGX                       ; Convert to binary
  1502.         jc SSG2A                        ; Error if carry
  1503.         or al,ah                        ; Merge the two nibbles
  1504.         cmp al,40H                      ; Only accept x'40' and up
  1505.         jae SSG3                        ; Jump if OK
  1506.  
  1507. ; ----- Jump here on any error with the CEDINT= string
  1508. SSG2A:
  1509.         mov al,1                        ; Return code 1
  1510.         jmp short SSG9
  1511.  
  1512. ; ----- OK, AL has the purported PCED interrupt number. Check it out.
  1513. SSG3:
  1514.         push ax                         ; Save int number
  1515.         mov ah,35H                      ; Get ISR address to ES:BX
  1516.         int 21H
  1517.         mov si,bx                       ; Move ISR offset to SI
  1518.         pop bx                          ; Recover int # (in BL)
  1519.  
  1520.         mov ax,es                       ; AX = ISR segment
  1521.         or ax,si                        ; Merge offset; AX=0 if not installed
  1522.         jz SSG9                         ; Return, AL=0 for not installed
  1523.  
  1524.         mov ax,es
  1525.         mov ds,ax                       ; DS:SI -> service routine
  1526.         add si,3                        ; DS:SI -> PCED signature
  1527.         cmp word ptr [si],'CD'          ; Check signature
  1528.         jne SSG5                        ; Uh-oh, someone else using vector
  1529.  
  1530.         mov cx,16                       ; # bytes to checksum
  1531.         xor al,al                       ; Clear sum
  1532. SSG4:   add al,[si]
  1533.         inc si
  1534.         loop SSG4
  1535.         cmp al,0FCH                     ; Test checksum
  1536.         jne SSG5                        ; Uh-oh again
  1537.  
  1538.         mov al,bl                       ; Got it! Get int # to AL
  1539.         jmp short SSG9
  1540.  
  1541. ; ----- If here, someone else stole the vector
  1542. SSG5:
  1543.         mov al,2                        ; Return code 2
  1544.  
  1545. ; ----- Common exit.  AL has return code.
  1546. SSG9:
  1547.         mov es,dx
  1548.         pop ds
  1549.         pop di
  1550.         pop si
  1551.         pop dx
  1552.         pop cx
  1553.         pop bx
  1554.         ret
  1555.  
  1556. ; ----- Convert AL from ASCII to binary; return CF=1 if not a hex digit
  1557. SSGX:
  1558.         cmp al,'a'                      ; Ensure uppercase
  1559.         jb SSGX1
  1560.         cmp al,'z'
  1561.         ja SSGX1
  1562.         sub al,32
  1563. SSGX1:
  1564.         cmp al,'F'                      ; Error if > 'F'
  1565.         ja SSGXErr
  1566.         sub al,'0'                      ; First conversion
  1567.         jc SSGXErr                      ; Error if < '0'
  1568.         cmp al,9                        ; OK if <= 9
  1569.         jbe SSGX8
  1570.         sub al,7                        ; Second conversion
  1571.         cmp al,10                       ; Error if 2nd cnvrt results in < 10
  1572.         jb SSGXErr
  1573. SSGX8:  clc
  1574. SSGX9:  ret
  1575.  
  1576. SSGXErr:
  1577.         stc
  1578.         jmp SSGX9
  1579.  
  1580.